package com.cx.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 *
 *
 */
public class NioSelectorServer {

//    static List<SocketChannel> channelList = new ArrayList<>();

    public static void main(String[] args) throws IOException {

        final ServerSocketChannel serverSocket = ServerSocketChannel.open();
        // 启动服务，绑定9000端口
        serverSocket.socket().bind(new InetSocketAddress(9000));
        // 设置serverSocket 为非阻塞
        serverSocket.configureBlocking(false);
        // 打开Selector多路复用器
        final Selector selector = Selector.open();
        // 注册serverSocket accept 事件
        serverSocket.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务启动完成");
        while (true) {
            // 阻塞 等待处理事件的发生
            selector.select();
            // 获取 selector 中注册的全部事件的key (此处是监听到了有事件变化的key)
            final Set<SelectionKey> selectionKeys = selector.selectedKeys();
            final Iterator<SelectionKey> iterator = selectionKeys.iterator();

            // 遍历 处理事件key
            while (iterator.hasNext()) {
                final SelectionKey key = iterator.next();
                if(key.isAcceptable()){
                    // 表示为 accept 接收连接事件
                    final ServerSocketChannel server = (ServerSocketChannel) key.channel();
                    final SocketChannel socketChannel = server.accept();
                    socketChannel.configureBlocking(false);
                    // 将此连接客户端的 socketChannel 注册读事件 (若要发 可注册写事件)
                    socketChannel.register(selector,SelectionKey.OP_READ);
//                    socketChannel.register(selector,SelectionKey.OP_WRITE);
                    System.out.println("客户端连接成功");
                }else if(key.isReadable()){
                    // 表示为 read 接收读事件
                    final SocketChannel sc = (SocketChannel)key.channel();
                    final ByteBuffer buffer = ByteBuffer.allocate(128);
                    final int len = sc.read(buffer);
                    if (len > 0) {
                        System.out.println("接收到消息：" + new String(buffer.array()));
                    } else if (len == -1) {
                        // 如果客户端断开，关闭socket
                        iterator.remove();
                        System.out.println("客户端断开");
                        sc.close();
                        continue;
                    }
                }
                // 移除本次处理的 事件key ,防止下次 select重复处理
                iterator.remove();
            }
        }
    }
}
